/*
 * Converter.c
 *
 *  Created on: Oct 28, 2011
 *      Author: Christopher Wood, Max Macri
 *
 *  Convert analog signal from the signal generator to digital values.
 */

// Module includes
#include <time.h>
#include <signal.h>
#include <errno.h>
#include <sys/siginfo.h>
#include <unistd.h>       /* for sleep() */
#include <hw/inout.h>     /* for in*() and out*() functions */
#include <sys/neutrino.h> /* for ThreadCtl() */
#include <sys/mman.h>     /* for mmap_device_io() */
#include <stdlib.h>
#include <stdio.h>
#include "Converter.h"

// Constants used by the program
#define BASE_ADDRESS					(0x280)
#define LSB_BASE_ADDRESS				(BASE_ADDRESS)
#define MSB_BASE_ADDRESS				(BASE_ADDRESS + 0x01)
#define BASE_OUTPUT_VAL					(0x80)
#define AD_CHANNEL_ADDRESS				(BASE_ADDRESS + 0x02)
#define AD_CHANNEL_VAL					(0x44)
#define ANALOG_INPUT_STATUS_ADDRESS		(BASE_ADDRESS + 0x03)
#define ANALOG_INPUT_STATUS_VAL			(0x00)
#define ANALOG_INPUT_WAIT_BIT			(0b00100000)
#define AD_RANGE						(32768)
#define INPUT_RANGE						(10)

// Private data handles that are shared by various routines inside the converter
uintptr_t lsbHandle;
uintptr_t msbHandle;
uintptr_t adChannelHandle;
uintptr_t analogInputStatusHandle;

// Intialize the A/D input register to capture analog data.
//--------------------------------------------------------------       
void InitADRegister(void)
{
	int privityErr;

	// Give this thread root permissions to access the hardware
	privityErr = ThreadCtl( _NTO_TCTL_IO, NULL );
	if ( privityErr == -1 )
	{
		fprintf( stderr, "can't get root permissions\n" );
		exit(-1);
	}

	// Get a handle to the LSB of the A/D register
	lsbHandle = mmap_device_io( PORT_LENGTH, LSB_BASE_ADDRESS );

	// Get a handle to the MSB of the A/D register
	msbHandle = mmap_device_io( PORT_LENGTH, MSB_BASE_ADDRESS );

	// Get a handle to the A/D channel register
	adChannelHandle = mmap_device_io( PORT_LENGTH, AD_CHANNEL_ADDRESS );

	// Set the board to the specified channel(s)
	out8( adChannelHandle, AD_CHANNEL_VAL );

	// Get a handle to the analog input status register
	analogInputStatusHandle = mmap_device_io( PORT_LENGTH, ANALOG_INPUT_STATUS_ADDRESS );

	// Select the input range for the A/D converter
	out8( analogInputStatusHandle, ANALOG_INPUT_STATUS_VAL );	// +10V, -10V range (gain of 0)
}

// Perform an A/D conversion to get a digital value from the 
// input signal.
//--------------------------------------------------------------      
void PerformADConversion(void)
{
	while ((in8(analogInputStatusHandle) & ANALOG_INPUT_WAIT_BIT) != 0)
	{
		// busy waiting
	}

	// start the A/D conversion
	out8( lsbHandle, BASE_OUTPUT_VAL );

	while ((in8(analogInputStatusHandle) & BASE_OUTPUT_VAL) != 0)
	{
		// busy waiting
	}
}

// Retrieve the 16-bit A/D value.
//-------------------------------------------------------------- 
INT16 ReadADData(void)
{
	INT8 lsbData = in8(lsbHandle);
	INT8 msbData = in8(msbHandle);
	INT16 dataToReturn = (msbData << 8) + lsbData;

	return dataToReturn;
}

// Convert a 16-bit A/D value to a digital voltage level.
//--------------------------------------------------------------       
float ConvertADData(INT16 adBoardData)
{
	double convertedInputVoltage = (double)(adBoardData * INPUT_RANGE) / AD_RANGE;
	return convertedInputVoltage;
}
